﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Djs.Neuronic.Medium;

namespace Djs.Neuronic.Brain
{
    #region RecordCls : jedna základní datová třída, dovoluje data načítat z databáze i do databáze ukládat, na základě ID.
    /// <summary>
    /// RecordCls : jedna základní databázová třída, dovoluje data načítat z databáze i do databáze ukládat, na základě ID.
    /// Implementuje IRecord, přenáší jeho potřebné členy na svoje protected abstraktní nebo virtual členy.
    /// Má svoje ID, registruje IsDirty.
    /// Jde o bázovou třídu pro ostatní datové třídy, neobsahuje prostor ani pro svoje položky, ani pro ID2 které je vlastní položkám.
    /// Její paměťová náročnost je minimální.
    /// </summary>
    public abstract class RecordCls : IRecord
    {
        #region Virtual
        /// <summary>
        /// Identifikátor záznamu. 
        /// </summary>
        public virtual int Id { get; protected set; }
        /// <summary>
        /// Příznak změn dat v záznamu.
        /// Každá property ve své set metodě má nastavit IsDirty = true;.
        /// </summary>
        public virtual bool IsDirty { get; protected set; }
        /// <summary>
        /// Nastaví IsDirty = true
        /// </summary>
        protected virtual void SetDirty() { this.IsDirty = true; }
        /// <summary>
        /// Název sloupce obsahujícího ID
        /// </summary>
        protected virtual string ColumnId { get { return "id"; } }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString() { return "#" + this.Id.ToString(); }
        #endregion
        #region IRecord & abstract
        /// <summary>
        /// Metoda dostává data načtená z databáze (v objektu data) a uloží si je typově do svých property
        /// </summary>
        /// <param name="data"></param>
        protected abstract void Fill(RecordFillInfo data);
        /// <summary>
        /// Metoda připraví data ze svých property do předaného objektu, odkud budou zapsány do databáze.
        /// Metoda nemá řešit ID.
        /// </summary>
        /// <param name="data"></param>
        protected abstract void Save(RecordSaveInfo data);
        /// <summary>
        /// Metoda dostává data načtená z databáze (v objektu data) a uloží si je typově do svých property
        /// </summary>
        /// <param name="data"></param>
        void IRecordFill.Fill(RecordFillInfo data) { this._Fill(data); }
        /// <summary>
        /// Identifikátor záznamu. 
        /// Přes interface (IRecord) jej lze setovat (při zakládání nového záznamu do databáze dostane svoje ID).
        /// </summary>
        int IRecordSave.Id { get { return this.Id; } set { this.Id = value; } }
        /// <summary>
        /// Položky
        /// </summary>
        // IEnumerable<List<IRecord>> IRecord.Entries { get { return null; } }
        /// <summary>
        /// Příznak změn dat v záznamu.
        /// Každá property ve své set metodě má nastavit IsDirty = true;.
        /// Přes interface (IRecord) jej lze setovat (při ukládání záznamu do databáze se nuluje na false).
        /// </summary>
        bool IRecordSave.IsDirty { get { return this.IsDirty; } set { this.IsDirty = value; } }
        /// <summary>
        /// Metoda připraví data ze svých property do předaného objektu, odkud budou zapsány do databáze
        /// </summary>
        /// <param name="data"></param>
        void IRecordSave.Save(RecordSaveInfo data) { this._Save(data); }
        /// <summary>
        /// Privátní Fill: naplní ID a zavolá virtual Fill()
        /// </summary>
        /// <param name="data"></param>
        private void _Fill(RecordFillInfo data)
        {
            if (data.ContainColumn(this.ColumnId))
                this.Id = (int)data.Get(this.ColumnId);
            this.Fill(data);
            this.IsDirty = false;
        }
        /// <summary>
        /// Privátní Save: zavolá virtual Save()
        /// </summary>
        /// <param name="data"></param>
        private void _Save(RecordSaveInfo data)
        {
            this.Save(data);
        }
        #endregion
    }
    #endregion
    #region MasterRecordCls : třída pro prvky typu Master s položkami
    /// <summary>
    /// MasterRecordCls : třída pro prvky typu Master s položkami.
    /// Pro uložení sady položek se má používat třída EntriesDataList, jejímž generickým typem je třída záznamu položek.
    /// Třída MasterRecordCls musí přepsat abstraktní metodu GetEntries(name), jednoduše tak že vrátí odpovídající EntriesDataList položek.
    /// Třída EntriesDataList je jednak List položek, a jednak implementuje potřebné rozhraní IEntries, s nímž pracuje systém načítání / ukládání dat (DatabaseCls.ReadRecord).
    /// </summary>
    //public abstract class MasterRecordCls : RecordCls, IMasterRecord
    //{
    //    #region Lazy donačítání položek
    //    protected void EntriesLoad()
    //    {
    //        Stator.Database.ReadEntriesTo(this);
    //    }
    //    #endregion
    //    #region  property interface IMasterRecord.AllEntries, abstract metoda this.GetAllEntries()
    //    /// <summary>
    //    /// Konkrétní datová třída v této metodě vrátí soupis všech svých soupisů položek.
    //    /// Nejsnadnější je vrátit new IEntries [] { vyjmenovat objekty, které evidují položky }.
    //    /// Může vrátit null, pokud nemá žádné položky. Pak se nebude nic ukládat / načítat.
    //    /// Pokud objekt IMasterRecord chce, aby jeho položky byly načítány přímo, měl by vrátit ne null objekty.
    //    /// Pro ukládání položek se běžně využívá třída EntriesDataList, kde generikum je třída položek.
    //    /// Pokud objekt pracuje v režimu Lazy, pak má položkové seznamy NULL, a plní je až v případě první potřeby.
    //    /// Pak tedy v get accessoru položkových listů testuje NULL, a pokud je NULL pak vytvoří new() seznamy a zavolá metodu Database.ReadEntries(this).
    //    /// </summary>
    //    /// <param name="name"></param>
    //    /// <returns></returns>
    //    protected abstract IEnumerable<IEntries> GetAllEntries();
    //    IEnumerable<IEntries> IMasterRecord.AllEntries { get { return this.GetAllEntries(); } }
    //    #endregion
    //}
    #endregion
    #region EntriesDataList
    /// <summary>
    /// Třída obsahující položky jednoho typu pro jeden master záznam.
    /// S touto třídou komunikuje databáze při načítání/ukládání dat.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EntriesDataList<T> : DataList<T>, IEntries where T : IRecord
    {
        #region Konstruktory
        public EntriesDataList() : base() { }
        public EntriesDataList(int capacity) : base(capacity) { }
        public EntriesDataList(IEnumerable<T> collection) : base(collection) { }
        #endregion
        #region IEntries Members
        Type IEntries.ItemType { get { return this.ItemType; } }
        IEnumerable<IRecord> IEntries.EntriesToSave { get { return this.Items.Where(i => i.Id == 0 || i.IsDirty).Cast<IRecord>(); } }
        IEnumerable<IRecord> IEntries.EntriesToDelete { get { return this.Removed.Cast<IRecord>(); } }
        IEnumerable<IRecord> IEntries.EntriesLoaded { set { this.Store(value.Cast<T>()); } }
        #endregion
    }
    #endregion
}
